﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.UI;
using System.Xml.Serialization;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Configuration;
using System.Web.UI.HtmlControls;
using System.IO.Compression;
using System.Web;

namespace Carbon.Web.Forms
{
    internal static class InternalUtility
    {
        private static readonly Type GenericNullableType = typeof(Nullable<byte>).GetGenericTypeDefinition();

        public static Type ExtractTypeWithoutNullable(Type dataType)
        {
            if (dataType.IsGenericType && dataType.GetGenericTypeDefinition() == GenericNullableType)
            {
                return dataType.GetGenericArguments()[0];
            }
            else
            {
                return dataType;
            }
        }

        public static bool IsNullable(Type dataType)
        {
            if (dataType.IsGenericType && dataType.GetGenericTypeDefinition() == GenericNullableType)
                return true;
            if (!dataType.IsValueType)
                return true;
            return false;
        }

        public static byte[] Compress(byte[] data)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                using (GZipStream zip = new GZipStream(ms, CompressionMode.Compress))
                {
                    zip.Write(data, 0, data.Length);
                    zip.Close();
                    return ms.ToArray();
                }
            }
        }

        public static byte[] Decompress(byte[] data)
        {
            using (MemoryStream ms = new MemoryStream(data))
            {
                using (GZipStream zip = new GZipStream(ms, CompressionMode.Decompress))
                {
                    using (MemoryStream output = new MemoryStream())
                    {
                        byte[] buffer = new byte[2048];
                        int read = 0;
                        while ((read = zip.Read(buffer, 0, buffer.Length)) > 0)
                        {
                            output.Write(buffer, 0, read);
                        }

                        return output.ToArray();
                    }
                }

            }
        }

        public static String CompactSerialize<T>(T value)
        {
            LosFormatter formatter = new LosFormatter();
            using (StringWriter sw = new StringWriter())
            {
                formatter.Serialize(sw, value);

                return sw.ToString();
            }
        }

        public static byte[] CompactSerializeToByteArray<T>(T value)
        {
            ObjectStateFormatter formatter = new ObjectStateFormatter();
            using (MemoryStream memoryStream = new MemoryStream(50000))
            {
                formatter.Serialize(memoryStream, value);
                return memoryStream.ToArray();
            }
        }

        public static T CompactDeserializeFromByteArray<T>(byte[] value)
        {
            ObjectStateFormatter formatter = new ObjectStateFormatter();
            using (MemoryStream memoryStream = new MemoryStream(value))
            {
                return (T)formatter.Deserialize(memoryStream);
            }
        }

        public static T CompactDeserialize<T>(String value)
        {
            LosFormatter formatter = new LosFormatter();
            using (StringReader sr = new StringReader(value))
            {
                return (T)formatter.Deserialize(sr);
            }
        }

        public static byte[] BinarySerialize<TValue>(TValue value)
        {
            IFormatter formatter = new BinaryFormatter();
            byte[] result = null;
            using (Stream stream = new MemoryStream())
            {
                formatter.Serialize(stream, value);

                result = new byte[stream.Length];
                stream.Position = 0;
                stream.Read(result, 0, result.Length);

                stream.Flush();
                stream.Close();

                return result;
            }
        }

        public static TValue BinaryDeserialize<TValue>(byte[] data)
        {
            IFormatter formatter = new BinaryFormatter();
            using (Stream stream = new MemoryStream(data))
            {
                return (TValue)formatter.Deserialize(stream);
            }
        }

        public static String BinarySerializeToString<TValue>(TValue value)
        {
            return Convert.ToBase64String(BinarySerialize<TValue>(value));
        }

        public static TValue BinaryDeserializeFromString<TValue>(String data)
        {
            return BinaryDeserialize<TValue>(Convert.FromBase64String(data));
        }

        public static String MergeCssClasses(String class1, String class2)
        {
            if (!string.IsNullOrEmpty(class2) && !string.IsNullOrEmpty(class1))
                return class1 + " " + class2;
            else if (!string.IsNullOrEmpty(class1))
                return class1;
            else if (!string.IsNullOrEmpty(class2))
                return class2;
            else
                return string.Empty;
        }

        public static string EncodeJavascriptString(string s)
        {
            StringBuilder sb = new StringBuilder();

            foreach (char c in s)
            {
                switch (c)
                {
                    case '\"':
                        sb.Append("\\\"");
                        break;
                    case '\\':
                        sb.Append("\\\\");
                        break;
                    case '\b':
                        sb.Append("\\b");
                        break;
                    case '\f':
                        sb.Append("\\f");
                        break;
                    case '\n':
                        sb.Append("\\n");
                        break;
                    case '\r':
                        sb.Append("\\r");
                        break;
                    case '\t':
                        sb.Append("\\t");
                        break;
                    default:
                        int i = (int)c;
                        if (i < 32 || i > 127)
                        {
                            sb.AppendFormat("\\u{0:X04}", i);
                        }
                        else
                        {
                            sb.Append(c);
                        }
                        break;
                }
            }

            return sb.ToString();
        }

        public static void EnsureCssInclude(Page page, Type type, String key, String url)
        {
            if (!page.ClientScript.IsClientScriptBlockRegistered(type, key))
            {
                HtmlHead head = (HtmlHead)page.Header;
                HtmlLink link = new HtmlLink();

                link.Attributes.Add("href", url);
                link.Attributes.Add("type", "text/css");
                link.Attributes.Add("rel", "stylesheet");
                head.Controls.Add(link);

                page.ClientScript.RegisterClientScriptBlock(type, key, "", false);
            }
        }

        public static String UrlEncode(String value)
        {
            return HttpUtility.UrlEncode(value);
        }
    }
}
